import numpy as np
from scipy.spatial.distance import pdist, squareform
import pandas as pd
import time

start_time = time.time()
""" 参数实验需更改4个参数 """

""" 加载特征数据 """
#####################################################################

# node_features_path = 'data/ClfSim.csv'
node_features_path = 'data/HGSim.csv'

node_df = pd.read_csv(node_features_path)
features = node_df[['sim']].values.flatten()

# 计算全节点距离矩阵
distance_matrix = squareform(pdist(features.reshape(-1, 1), metric='euclidean'))
n_nodes = distance_matrix.shape[0]

# 生成三元组格式
xx = []
for i in range(n_nodes):
    for j in range(i+1, n_nodes):  # 避免重复记录
        xx.append([i+1, j+1, distance_matrix[i, j]])  
xx = np.array(xx)

# 构建对称距离矩阵（保留原始处理逻辑）
ND = n_nodes  # 最大节点数即为矩阵维度
dist = np.zeros((ND, ND), dtype=float)
for d in xx:
    i, j = int(d[0])-1, int(d[1])-1  # 转换回0-based索引
    dist[i][j] = d[2]
    dist[j][i] = d[2]  # 对称填充

# 计算截断距离
N = xx.shape[0]

""" 占比参数  """
#####################################################################

percent = 2
position = int(np.round(N * percent / 100.0) - 1)
sda = np.sort(xx[:, 2])
dc = sda[position]
rho = np.zeros((ND,), 'float')

# 绘制密度图
for i in np.arange(ND-1):
    for j in np.arange(i+1, ND):
        tmp = np.exp(- (dist[i,j]/dc)**2)
        rho[i] += tmp
        rho[j] += tmp

# 生成最小距离
maxd = dist.max().max()
print ('maxd: %r' % maxd)

rho_sorted,ordrho = np.sort(rho)[::-1],np.argsort(rho)[::-1]
delta,nneigh = np.zeros((ND,), 'float'),np.zeros((ND,), 'float')
delta[ordrho[0]] = -1
for ii in np.arange(1, ND):
    delta[ordrho[ii]] = maxd
    for jj in np.arange(ii):
        if dist[ordrho[ii],ordrho[jj]] < delta[ordrho[ii]]:
            delta[ordrho[ii]] = dist[ordrho[ii],ordrho[jj]]
            nneigh[ordrho[ii]] = ordrho[jj]
delta[ordrho[0]] = delta.ravel().max()


""" #rho（局部密度）和delta（到更高密度点的距离） """
#####################################################################


# rhomin,deltamin=100,0.8 #clf
rhomin,deltamin=50,0.7#HG
# print("rhomin: %r\tdeltamin: %r" % (rhomin, deltamin))
NCLUST=0
cl = np.ndarray((ND,),"int")

cl[:] = -1
icl = []



# 找到聚类中心
for i in np.arange(ND):
    if rho[i] > rhomin and delta[i] > deltamin:
        NCLUST += 1
        cl[i] = NCLUST-1
        icl.append(i)
print ("聚类数: %r" % NCLUST)


for i in range(ND):  # 使用 range 替代 np.arange
    current_idx = ordrho[i]
    if cl[current_idx] == -1:
        neighbor_idx = int(nneigh[current_idx])  # 确保索引为整数
        cl[current_idx] = cl[neighbor_idx]

# halo
halo = cl.copy()
if NCLUST > 1:
    bord_rho = np.zeros((NCLUST,),"float")
    for i in np.arange(ND-1):
        for j in np.arange(i+1,ND):
            if cl[i] != cl[j] and dist[i,j] <= dc:
                rho_aver = (rho[i]+rho[j]) / 2.
                if rho_aver > bord_rho[cl[i]]:
                    bord_rho[cl[i]] = rho_aver
                if rho_aver > bord_rho[cl[j]]:
                    bord_rho[cl[j]] = rho_aver
    for i in np.arange(ND):
        if rho[i] < bord_rho[cl[i]]:
            halo[i] = -1
for i in np.arange(NCLUST):
    nc,nh=0,0
    for j in np.arange(ND):
        if cl[j] == i:
            nc+=1
        if halo[j] == i:
            nh+=1
    print ("CLUSTER: %d CENTER: %d (%.4f,%4f) ELEMENTS: %d CORE: %d HALO: %d" % (i+1,icl[i],rho[icl[i]],delta[icl[i]],nc,nh,nc-nh))

""" 输出 """
#####################################################################
node_df["cluster"] = cl        
node_df["is_halo"] = np.where(halo == -1, -1, 1)

# node_df.to_csv('data/ClfDPC.csv', index=False)


#计算精度

def calculate_metrics4_df(pred, y):
    """ 计算指标值 """
    # 将 DataFrame 列转换为 NumPy 数组
    pred = np.array(pred)
    y = np.array(y)

    # 计算混淆矩阵的各项
    TP = np.sum((pred == 1) & (y == 1))
    TN = np.sum((pred == 0) & (y == 0))
    FP = np.sum((pred == 1) & (y == 0))
    FN = np.sum((pred == 0) & (y == 1))
    # # 计算混淆矩阵的各项，如果聚类指标跟Yb不一致
    # TP = np.sum((pred == 0) & (y == 1))
    # TN = np.sum((pred == 1) & (y == 0))
    # FP = np.sum((pred == 0) & (y == 0))
    # FN = np.sum((pred == 1) & (y == 1))

    # # 第二种
    # TP = np.sum(np.logical_or(pred == 0, pred == 2) & (y == 1))
    # TN = np.sum((pred == 1) & (y == 0))
    # FP = np.sum(np.logical_or(pred == 0, pred == 2) & (y == 0))  
    # FN = np.sum((pred == 1) & (y == 1))
    print("TP：",TP,"FP：",FP,"FN：",FN,)
    
    # 计算准确率、精确率、召回率和 F1 分数
    acc1 = (TP + TN) / (TP + TN + FP + FN)
    precision1 = TP / (TP + FP) if (TP + FP) > 0 else 0
    recall1 = TP / (TP + FN) if (TP + FN) > 0 else 0
    f11 = 2 * precision1 * recall1 / (precision1 + recall1) if (precision1 + recall1) > 0 else 0
    return acc1, precision1, recall1, f11

    # 获取预测值和真实值,如果聚类数不等于2，则进行校正
pred = node_df["cluster"].values
y = node_df['Ture'].values
acc1,precision1, recall1, f11= calculate_metrics4_df(pred, y)
print('parameter1: {:.4f} {:.4f} {:.4f}'.format(precision1, recall1, f11))

print(f"总执行时间: {time.time()-start_time:.2f}秒")